﻿#include "syssignal.h"
#include <QDebug>
#include <fstream>
#include <QThread>
#include <QCoreApplication>


string mvcc="";
string mzone="";
string mtool="";
string mwobj="";
string mload="";
int currntrow=0;
string currentfunction="";
QMap<QString,QVector<double> > mtarget={};
QMap<string,QVector<double> > Jntparamet={};
QMap<string,QVector<double> > Posparamet={};
bool _Next=true;
LUA_STA status=LUA_FREE;
QString _mpro="";

SysSignal* SysSignal::sys_signal=nullptr;

static int JOINTTARGET(lua_State *L)//lua中创建全局变量到C中
{
    string name= lua_tostring(L,1);
    qDebug()<<"arg 1 name == "<<QString::fromStdString(name);
    QVector<double> data = gettablefromelua(L,2);
    QVector<double> data2 = gettablefromelua(L,3);
    for(int i=0;i<data2.size();++i)
    {
        data.push_back(data2.at(i));
    }
    Jntparamet[name]=data;
    lua_newtable(L);
    for(int i=0;i<data.size();++i)
    {
        lua_pushnumber(L,data.at(i));
        lua_rawseti(L,-2,i+1);
    }
    lua_setglobal(L,name.c_str());
    return 1;
}
static int ROBTARGET(lua_State* L)
{
    string name= lua_tostring(L,1);
    qDebug()<<"arg 1 name == "<<QString::fromStdString(name);
    QVector<double> data = gettablefromelua(L,2);
    QVector<double> data2 = gettablefromelua(L,3);
    QVector<double> data3 = gettablefromelua(L,4);
    QVector<double> data4 = gettablefromelua(L,5);
    for(int i=0;i<data2.size();++i)
    {
        data.push_back(data2.at(i));
    }
    for(int i=0;i<data3.size();++i)
    {
        data.push_back(data3.at(i));
    }
    for(int i=0;i<data4.size();++i)
    {
        data.push_back(data4.at(i));
    }
    double t = lua_tonumber(L,6);
    data.push_back(t);
    Posparamet[name]=data;

    qDebug()<<"ROBTARGET "<< data;
    lua_newtable(L);
    for(int i=0;i<data.size();++i)
    {
        lua_pushnumber(L,data.at(i));
        lua_rawseti(L,-2,i+1);
    }
    lua_setglobal(L,name.c_str());
    return 1;
}

bool SysSignal::load_file(string path)
{
    ifstream ifs;
    ifs.open(path,ios::in);
    _mpro.clear();
    if(ifs.is_open())
    {
        string pro;
        while(getline(ifs,pro))
        {
            _mpro.append(QString::fromStdString(pro));
        }
        ifs.close();
    }
    else
    {
        ifs.close();
        return false;
    }
    luainit();
    int ret = luaL_loadfile(Lu,path.c_str());
    if(ret)
    {
        QString str="Error: load file error"+QString::fromStdString(lua_tostring(Lu,-1));
        emit sig_stringMsg(str);
        qDebug()<<"load file error"<<lua_tostring(Lu,-1);
        return false;
    }
    return true;
}

void SysSignal::waitforNext()
{
    while (!_Next) {
        //QThread::currentThread()->msleep(1);
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
    }
}

void SysSignal::load_string()
{
    qDebug()<<"SysSignal::load_string"<<"lua_script thread id == ";
    mpro = _mpro.toStdString();
    if(mpro.empty())
        return;
    luainit();
    int ret=luaL_loadstring(Lu,mpro.c_str());
    //int ret= luaL_load(Lu,&reader,pro.c_str());
    if(ret != LUA_OK)
    {
        status=LUA_ERROR;
        qDebug()<<"pro error!"<<lua_tostring(Lu,-1);
        QString str="Error: program error!"+QString::fromStdString(lua_tostring(Lu,-1));
        emit sig_stringMsg(str);
        _mpro.clear();
        return;
    }
    else
    {
        QString str="Info: program load success!";
        emit sig_stringMsg(str);
        mpro = pptomain(_mpro).toStdString();
        status=LUA_WAIT;
        qDebug()<<"program load success!";
    }
    return;
}

void SysSignal::execute()//程序执行器，执行lua代码
{
    if(_mpro.isEmpty())  // || status != LUA_WAIT
    {
        QString str="Info: can not find a lua program for execute!";
        emit sig_stringMsg(str);
        qDebug()<<"can not find a lua program for execute!";
        return;
    }
    load_string();
    status=LUA_RUN;
    if(lua_pcall(Lu,0,0,0)!=0)
    {
        QString str="Error: some error about lua program execute!"+QString::fromStdString(lua_tostring(Lu,-1));
        emit sig_stringMsg(str);
        qDebug()<<"Error: some error about lua program execute!"<<lua_tostring(Lu,-1);
        lua_close(Lu);
        return;
    }

    lua_getglobal(Lu,"main");
    //lua_sethook(Lu,Lua_script::hook,LUA_HOOKLINE,0);
    lua_pcall(Lu,0,0,0);
    lua_close(Lu);

    return;
}

void SysSignal::defglobal()
{
    for(int i=0;i<RobZone.size();++i)
    {
        lua_pushstring(Lu,RobZone.at(i).c_str());
        lua_setglobal(Lu,RobZone.at(i).c_str());
    }
    for(int i=0;i<RobVcc.size();++i)
    {
        lua_pushstring(Lu,RobVcc.at(i).c_str());
        lua_setglobal(Lu,RobVcc.at(i).c_str());
    }
    for(int i=0;i<RobTool.size();++i)
    {
        lua_pushstring(Lu,RobTool.at(i).c_str());
        lua_setglobal(Lu,RobTool.at(i).c_str());
    }
    for(int i=0;i<RobWobj.size();++i)
    {
        lua_pushstring(Lu,RobWobj.at(i).c_str());
        lua_setglobal(Lu,RobWobj.at(i).c_str());
    }
    for(int i=0;i<RobLoad.size();++i)
    {
        lua_pushstring(Lu,RobLoad.at(i).c_str());
        lua_setglobal(Lu,RobLoad.at(i).c_str());
    }
}

QString SysSignal::pptomain(QString pro)
{
    QString mainpro;
    QString functionstr;
    if(pro.contains("function main"))
    {
        return pro;
    }
    else
    {
        QStringList list=pro.split("\n");
        qDebug()<<list;
        bool infunction=false;
        int endindex=0;
        QString* current = &mainpro;
        for(int i=0;i<list.size();++i)
        {
            QString temp=list.at(i).trimmed();
            if(temp.contains(" function ") || temp.contains("local function "))
            {
                infunction=true;
                current= &functionstr;
                current->append(temp);
                current->append("\n");
            }
            else if(temp == "end")
            {
                if(endindex==0)
                {
                    infunction=false;
                    current->append(temp);
                    current->append("\n");
                    current= &mainpro;
                }
                else
                {
                    endindex--;
                    current->append(temp);
                    current->append("\n");
                }
            }
            else if(temp.startsWith("if(") || temp.startsWith("while(") || temp.startsWith("for "))
            {
                endindex++;
                current->append(temp);
                current->append("\n");
            }
            else
            {
                current->append(temp);
                current->append("\n");
            }

        }
    }

    if(functionstr.contains(" GLOBALDATA_DEFINE()"))
    {
        mainpro.prepend("function main()\n GLOBALDATA_DEFINE()\n");
    }else
    {
        mainpro.prepend("function main()\n");
    }
    mainpro.append("end");

    qDebug()<<"main function is : "<<mainpro;
    qDebug()<<"function is : "<<functionstr;
    functionstr.append(mainpro);

    return functionstr;
}

void SysSignal::luainit()
{
    Lu= luaL_newstate();
    luaL_openlibs(Lu);
    luaopen_string(Lu);
    luaopen_table(Lu);
    luaopen_base(Lu);
    luaopen_debug(Lu);
    luaopen_io(Lu);
    luaopen_package(Lu);
    lua_register(Lu,"JOINTTARGET",JOINTTARGET);//movej必须要static
    lua_register(Lu,"ROBTARGET",ROBTARGET);//movej必须要static
    lua_register(Lu,"MoveAbsJ",SysSignal::MoveAbsJ);
    lua_register(Lu,"MoveL",SysSignal::MoveL);
    lua_register(Lu,"MoveC",SysSignal::MoveC);
    lua_register(Lu,"MoveP",SysSignal::MoveP);
    defglobal();
    _Next=false;
}

int SysSignal::MoveAbsJ(lua_State *L)
{
    qDebug()<<"this is MoveAbsJ execute***!";
    if(lua_istable(L,1))
    {
        QVector<double> data= gettablefromelua(L,1);
        qDebug()<<"move absj paramet 1 == " << data;
        mvcc= lua_tostring(L,2);
        qDebug()<<"move absj paramet 2 == " << QString::fromStdString(mvcc);
        mzone= lua_tostring(L,3);
        qDebug()<<"move absj paramet 3 == " << QString::fromStdString(mzone);
        mtool= lua_tostring(L,4);
        qDebug()<<"move absj paramet 4 == " << QString::fromStdString(mtool);
        mwobj= lua_tostring(L,5);
        qDebug()<<"move absj paramet 5 == " << QString::fromStdString(mwobj);
        mload= lua_tostring(L,6);
        qDebug()<<"move absj paramet 6 == " << QString::fromStdString(mload);
        SysSignal::instance()->targetChanged("MoveAbsJ",data);
        _Next=false;
        waitforNext();

    }
    else
    {
        qDebug()<<"Error:MoveAbsJ arg 1 erorr! ";
    }
    return 1;
}

int SysSignal::MoveL(lua_State *L)
{
    if(lua_istable(L,1))
    {
        //int len = luaL_len(L,1);
        QVector<double> data= gettablefromelua(L,1);
        qDebug()<<"moveL paramet 1 == " << data;
        mvcc= lua_tostring(L,2);
        //qDebug()<<"move absj paramet 2 == " << QString::fromStdString(vcc);
        mzone= lua_tostring(L,3);
        //qDebug()<<"move absj paramet 3 == " << QString::fromStdString(zone);
        mtool= lua_tostring(L,4);
        //qDebug()<<"move absj paramet 4 == " << QString::fromStdString(tool);
        mwobj= lua_tostring(L,5);
        //qDebug()<<"move absj paramet 5 == " << QString::fromStdString(wobj);
        mload= lua_tostring(L,6);
        //qDebug()<<"move absj paramet 6 == " << QString::fromStdString(load);
        SysSignal::instance()->targetChanged("MoveL",data);
        _Next=false;
        waitforNext();
    }
    else
    {
        qDebug()<<"Error:MoveL arg 1 erorr! ";
    }
    return 1;
}

int SysSignal::MoveC(lua_State *L)
{
    if(lua_istable(L,1))
    {
        //int len = luaL_len(L,1);
        QVector<double> data1= gettablefromelua(L,1);
        qDebug()<<"movec paramet 1 == " << data1;
        QVector<double> data2= gettablefromelua(L,2);
        qDebug()<<"movec paramet 1 == " << data1;
        for(int i=0;i<data2.size();++i)
        {
            data1.push_back(data2.at(i));
        }
        mvcc= lua_tostring(L,3);
        mzone= lua_tostring(L,4);
        mtool= lua_tostring(L,5);
        mwobj= lua_tostring(L,6);
        mload= lua_tostring(L,7);
        SysSignal::instance()->targetChanged("MoveC",data1);
        _Next=false;
        waitforNext();
    }
    else
    {
        qDebug()<<"Error:MoveC arg 1 erorr! ";
    }
    return 1;
}

int SysSignal::MoveP(lua_State *L)
{
    if(lua_istable(L,1))
    {
        QVector<double> data= gettablefromelua(L,1);
        qDebug()<<"moveL paramet 1 == " << data;
        mvcc= lua_tostring(L,2);
        mzone= lua_tostring(L,3);
        mtool= lua_tostring(L,4);
        mwobj= lua_tostring(L,5);
        mload= lua_tostring(L,6);
        SysSignal::instance()->targetChanged("MoveP",data);
        _Next=false;
        waitforNext();
    }
    else
    {
        qDebug()<<"Error:arg 1 erorr! ";
    }
    return 1;
}

void SysSignal::hook(lua_State *L, lua_Debug *ar)
{
    if (ar->event == LUA_HOOKLINE) {
        const char *name = lua_getlocal(L, ar, 1);
        if (name == NULL) {
            name = "?";
        }
        else
            SysSignal::instance()->setcurrentfunc(name);
        int line = (int)ar->currentline;
        SysSignal::instance()->setexecuteline(line);
        printf("%s(%d)\n", name, (int)ar->currentline);
    }
}


QVector<double> gettablefromelua(lua_State *L, int index)
{
    int len = luaL_len(L,index);
    QVector<double> data;
    for(int i=0;i<len;++i)
    {
        lua_pushnumber(L,i+1);
        lua_gettable(L,index);
        data.push_back(lua_tonumber(L,-1));
        lua_pop(L,1);
    }
    qDebug()<<data;
    return data;
}

SysSignal::SysSignal(QObject *parent):QObject(parent)
{
    Lu = luaL_newstate();
}

SysSignal *SysSignal::instance()
{
    if(sys_signal==nullptr)
    {
        sys_signal = new SysSignal();
    }
    return sys_signal;
}

void SysSignal::targetChanged(QString key, QVector<double> data)
{
    qDebug()<<"SysSignal::targetChanged"<<key;
    if(key=="MoveAbsJ")
    {
        mtarget[key]=data;
        emit sig_movej();
    }
    else if(key=="MoveL")
    {
        mtarget[key]=data;
        emit sig_moveL();
    }
    else if(key=="MoveP")
    {
        mtarget[key]=data;
        emit sig_movep();
    }
    else if(key=="MoveC")
    {
        mtarget[key]=data;
        emit sig_moveC();
    }
    else
    {
        QString str="Error: unkonw move command!";
        qDebug()<<str;
    }
}

QVector<double> SysSignal::gettarget(QString key)
{
    if(mtarget.contains(key))
        return mtarget[key];
}

void SysSignal::setexecuteline(int line)
{
    currntrow=line;
    qDebug()<<"current line "<<line;
    emit sig_runrowchanged(line);
}

void SysSignal::setcurrentfunc(string func)
{
    currentfunction=func;
    qDebug()<<"current function "<<QString::fromStdString(func);
    emit sig_runfuncchanged(QString::fromStdString(func));
}

